*
* @file
*/
-use \Cdb\Exception as CdbException;
-use \Cdb\Reader as CdbReader;
+use MediaWiki\MediaWikiServices;
/**
- * The interwiki class
- * All information is loaded on creation when called by Interwiki::fetch( $prefix ).
- * All work is done on slave, because this should *never* change (except during
- * schema updates etc, which aren't wiki-related)
+ * Value object for representing interwiki records.
*/
class Interwiki {
- // Cache - removes oldest entry when it hits limit
- protected static $smCache = [];
- const CACHE_LIMIT = 100; // 0 means unlimited, any other value is max number of entries.
/** @var string The interwiki prefix, (e.g. "Meatball", or the language prefix "de") */
protected $mPrefix;
/**
* Check whether an interwiki prefix exists
*
+ * @deprecated since 1.28, use InterwikiLookup instead
+ *
* @param string $prefix Interwiki prefix to use
* @return bool Whether it exists
*/
public static function isValidInterwiki( $prefix ) {
- $result = self::fetch( $prefix );
-
- return (bool)$result;
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->isValidInterwiki( $prefix );
}
/**
* Fetch an Interwiki object
*
+ * @deprecated since 1.28, use InterwikiLookup instead
+ *
* @param string $prefix Interwiki prefix to use
* @return Interwiki|null|bool
*/
public static function fetch( $prefix ) {
- global $wgContLang;
-
- if ( $prefix == '' ) {
- return null;
- }
-
- $prefix = $wgContLang->lc( $prefix );
- if ( isset( self::$smCache[$prefix] ) ) {
- return self::$smCache[$prefix];
- }
-
- global $wgInterwikiCache;
- if ( $wgInterwikiCache ) {
- $iw = Interwiki::getInterwikiCached( $prefix );
- } else {
- $iw = Interwiki::load( $prefix );
- if ( !$iw ) {
- $iw = false;
- }
- }
-
- if ( self::CACHE_LIMIT && count( self::$smCache ) >= self::CACHE_LIMIT ) {
- reset( self::$smCache );
- unset( self::$smCache[key( self::$smCache )] );
- }
-
- self::$smCache[$prefix] = $iw;
-
- return $iw;
- }
-
- /**
- * Resets locally cached Interwiki objects. This is intended for use during testing only.
- * This does not invalidate entries in the persistent cache, as invalidateCache() does.
- * @since 1.27
- */
- public static function resetLocalCache() {
- static::$smCache = [];
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->fetch( $prefix );
}
/**
* Purge the cache (local and persistent) for an interwiki prefix.
+ *
* @param string $prefix
* @since 1.26
*/
public static function invalidateCache( $prefix ) {
- $cache = ObjectCache::getMainWANInstance();
- $key = wfMemcKey( 'interwiki', $prefix );
- $cache->delete( $key );
- unset( static::$smCache[$prefix] );
- }
-
- /**
- * Fetch interwiki prefix data from local cache in constant database.
- *
- * @note More logic is explained in DefaultSettings.
- *
- * @param string $prefix Interwiki prefix
- * @return Interwiki
- */
- protected static function getInterwikiCached( $prefix ) {
- $value = self::getInterwikiCacheEntry( $prefix );
-
- $s = new Interwiki( $prefix );
- if ( $value ) {
- // Split values
- list( $local, $url ) = explode( ' ', $value, 2 );
- $s->mURL = $url;
- $s->mLocal = (bool)$local;
- } else {
- $s = false;
- }
-
- return $s;
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->invalidateCache( $prefix );
}
/**
- * Get entry from interwiki cache
+ * Returns all interwiki prefix definitions.
*
- * @note More logic is explained in DefaultSettings.
- *
- * @param string $prefix Database key
- * @return bool|string The interwiki entry or false if not found
- */
- protected static function getInterwikiCacheEntry( $prefix ) {
- global $wgInterwikiScopes, $wgInterwikiFallbackSite;
- static $site;
-
- $value = false;
- try {
- // Resolve site name
- if ( $wgInterwikiScopes >= 3 && !$site ) {
- $site = self::getCacheValue( '__sites:' . wfWikiID() );
- if ( $site == '' ) {
- $site = $wgInterwikiFallbackSite;
- }
- }
-
- $value = self::getCacheValue( wfMemcKey( $prefix ) );
- // Site level
- if ( $value == '' && $wgInterwikiScopes >= 3 ) {
- $value = self::getCacheValue( "_{$site}:{$prefix}" );
- }
- // Global Level
- if ( $value == '' && $wgInterwikiScopes >= 2 ) {
- $value = self::getCacheValue( "__global:{$prefix}" );
- }
- if ( $value == 'undef' ) {
- $value = '';
- }
- } catch ( CdbException $e ) {
- wfDebug( __METHOD__ . ": CdbException caught, error message was "
- . $e->getMessage() );
- }
-
- return $value;
- }
-
- private static function getCacheValue( $key ) {
- global $wgInterwikiCache;
- static $reader;
- if ( $reader === null ) {
- $reader = is_array( $wgInterwikiCache ) ? false : CdbReader::open( $wgInterwikiCache );
- }
- if ( $reader ) {
- return $reader->get( $key );
- } else {
- return isset( $wgInterwikiCache[$key] ) ? $wgInterwikiCache[$key] : false;
- }
- }
-
- /**
- * Load the interwiki, trying first memcached then the DB
- *
- * @param string $prefix The interwiki prefix
- * @return Interwiki|bool Interwiki if $prefix is valid, otherwise false
- */
- protected static function load( $prefix ) {
- global $wgInterwikiExpiry;
-
- $iwData = [];
- if ( !Hooks::run( 'InterwikiLoadPrefix', [ $prefix, &$iwData ] ) ) {
- return Interwiki::loadFromArray( $iwData );
- }
-
- if ( is_array( $iwData ) ) {
- $iw = Interwiki::loadFromArray( $iwData );
- if ( $iw ) {
- return $iw; // handled by hook
- }
- }
-
- $iwData = ObjectCache::getMainWANInstance()->getWithSetCallback(
- wfMemcKey( 'interwiki', $prefix ),
- $wgInterwikiExpiry,
- function ( $oldValue, &$ttl, array &$setOpts ) use ( $prefix ) {
- $dbr = wfGetDB( DB_SLAVE );
-
- $setOpts += Database::getCacheSetOptions( $dbr );
-
- $row = $dbr->selectRow(
- 'interwiki',
- Interwiki::selectFields(),
- [ 'iw_prefix' => $prefix ],
- __METHOD__
- );
-
- return $row ? (array)$row : '!NONEXISTENT';
- }
- );
-
- if ( is_array( $iwData ) ) {
- return Interwiki::loadFromArray( $iwData ) ?: false;
- }
-
- return false;
- }
-
- /**
- * Fill in member variables from an array (e.g. memcached result, Database::fetchRow, etc)
- *
- * @param array $mc Associative array: row from the interwiki table
- * @return Interwiki|bool Interwiki object or false if $mc['iw_url'] is not set
- */
- protected static function loadFromArray( $mc ) {
- if ( isset( $mc['iw_url'] ) ) {
- $iw = new Interwiki();
- $iw->mURL = $mc['iw_url'];
- $iw->mLocal = isset( $mc['iw_local'] ) ? (bool)$mc['iw_local'] : false;
- $iw->mTrans = isset( $mc['iw_trans'] ) ? (bool)$mc['iw_trans'] : false;
- $iw->mAPI = isset( $mc['iw_api'] ) ? $mc['iw_api'] : '';
- $iw->mWikiID = isset( $mc['iw_wikiid'] ) ? $mc['iw_wikiid'] : '';
-
- return $iw;
- }
-
- return false;
- }
-
- /**
- * Fetch all interwiki prefixes from interwiki cache
- *
- * @param null|string $local If not null, limits output to local/non-local interwikis
- * @return array List of prefixes
- * @since 1.19
- */
- protected static function getAllPrefixesCached( $local ) {
- global $wgInterwikiScopes, $wgInterwikiFallbackSite;
- static $site;
-
- wfDebug( __METHOD__ . "()\n" );
- $data = [];
- try {
- /* Resolve site name */
- if ( $wgInterwikiScopes >= 3 && !$site ) {
- $site = self::getCacheValue( '__sites:' . wfWikiID() );
-
- if ( $site == '' ) {
- $site = $wgInterwikiFallbackSite;
- }
- }
-
- // List of interwiki sources
- $sources = [];
- // Global Level
- if ( $wgInterwikiScopes >= 2 ) {
- $sources[] = '__global';
- }
- // Site level
- if ( $wgInterwikiScopes >= 3 ) {
- $sources[] = '_' . $site;
- }
- $sources[] = wfWikiID();
-
- foreach ( $sources as $source ) {
- $list = self::getCacheValue( '__list:' . $source );
- foreach ( explode( ' ', $list ) as $iw_prefix ) {
- $row = self::getCacheValue( "{$source}:{$iw_prefix}" );
- if ( !$row ) {
- continue;
- }
-
- list( $iw_local, $iw_url ) = explode( ' ', $row );
-
- if ( $local !== null && $local != $iw_local ) {
- continue;
- }
-
- $data[$iw_prefix] = [
- 'iw_prefix' => $iw_prefix,
- 'iw_url' => $iw_url,
- 'iw_local' => $iw_local,
- ];
- }
- }
- } catch ( CdbException $e ) {
- wfDebug( __METHOD__ . ": CdbException caught, error message was "
- . $e->getMessage() );
- }
-
- ksort( $data );
-
- return array_values( $data );
- }
-
- /**
- * Fetch all interwiki prefixes from DB
- *
- * @param string|null $local If not null, limits output to local/non-local interwikis
- * @return array List of prefixes
- * @since 1.19
- */
- protected static function getAllPrefixesDB( $local ) {
- $db = wfGetDB( DB_SLAVE );
-
- $where = [];
-
- if ( $local !== null ) {
- if ( $local == 1 ) {
- $where['iw_local'] = 1;
- } elseif ( $local == 0 ) {
- $where['iw_local'] = 0;
- }
- }
-
- $res = $db->select( 'interwiki',
- self::selectFields(),
- $where, __METHOD__, [ 'ORDER BY' => 'iw_prefix' ]
- );
-
- $retval = [];
- foreach ( $res as $row ) {
- $retval[] = (array)$row;
- }
-
- return $retval;
- }
-
- /**
- * Returns all interwiki prefixes
+ * @deprecated since 1.28, unused. Use InterwikiLookup instead.
*
* @param string|null $local If set, limits output to local/non-local interwikis
- * @return array List of prefixes
+ * @return array[] List of interwiki rows
* @since 1.19
*/
public static function getAllPrefixes( $local = null ) {
- global $wgInterwikiCache;
-
- if ( $wgInterwikiCache ) {
- return self::getAllPrefixesCached( $local );
- }
-
- return self::getAllPrefixesDB( $local );
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->getAllPrefixes( $local );
}
/**
return !$msg->exists() ? '' : $msg->text();
}
- /**
- * Return the list of interwiki fields that should be selected to create
- * a new Interwiki object.
- * @return string[]
- */
- public static function selectFields() {
- return [
- 'iw_prefix',
- 'iw_url',
- 'iw_api',
- 'iw_wikiid',
- 'iw_local',
- 'iw_trans'
- ];
- }
}